package com.hxl.tech.gateway.core.filter;


import com.hxl.tech.gateway.common.constant.AppConstant;
import com.hxl.tech.gateway.common.constant.Result;
import com.hxl.tech.gateway.core.exception.GatewayException;
import com.hxl.tech.gateway.core.util.CacheManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;


@Slf4j
@Component
@RequiredArgsConstructor
public class PrepareFilter implements GlobalFilter, Ordered {

    private Pattern versionPattern = Pattern.compile("v(\\d+)");

    private final CacheManager cacheManager;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        return exchange.getPrincipal().flatMap(p -> {
            JwtAuthenticationToken token = (JwtAuthenticationToken)p;
            Map<String, Object> map = token.getToken().getClaims();

            // 获取接口名称和版本号
            String apiPath = exchange.getRequest().getPath().value().substring(5);
            String[] paths = apiPath.split("/");
            String apiName = paths[0];
            String apiVersion = null;

            String appId = (String)map.get(AppConstant.CLIENT_ID);
            String merchantCode = (String)map.get(AppConstant.HEADER_OPEN_MERCHANT_CODE);
            Route route = cacheManager.get(merchantCode, appId, apiName, apiVersion);

            exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);
            ServerHttpRequest request = exchange.getRequest().mutate().headers((httpHeaders) -> {
                httpHeaders.set(AppConstant.HEADER_OPEN_APP_ID, appId);
                httpHeaders.set(AppConstant.HEADER_OPEN_MERCHANT_CODE, merchantCode);
            }).path(route.getUri().getPath().concat(apiPath.split(apiName)[1])).build();

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.putAll(request.getHeaders());
            request = new ServerHttpRequestDecorator(request) {
                @Override
                public HttpHeaders getHeaders() {
                    return httpHeaders;
                }
            };

            if(Objects.isNull(merchantCode) || Objects.isNull(appId) ){
                ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.BAD_REQUEST);
                return exchange.getResponse().setComplete();
            } else {
                return chain.filter(exchange.mutate().request(request).build()).subscriberContext(ctx -> {
                    ctx = ctx.put(AppConstant.APP_ID, appId);
                    ctx = ctx.put(AppConstant.API_NAME, route.getId());
                    ctx = ctx.put(AppConstant.MERCHANT_CODE, merchantCode);
                    return ctx;
                });
            }
        }).onErrorResume((e) -> {
            if(e instanceof GatewayException) {
                ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.BAD_REQUEST);
                return exchange.getResponse().setComplete();
            } else if (e instanceof ResponseStatusException) {
                log.error(e.getMessage(), e);
                ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.GATEWAY_TIMEOUT);
                return exchange.getResponse().setComplete();
            } else {
                log.error(e.getMessage(), e);
                ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.INTERNAL_SERVER_ERROR);
                return exchange.getResponse().setComplete();
            }
        }).then(Mono.fromRunnable(() -> {
            // 可以通过influxdb记录请求记录
            ServerHttpResponse response = exchange.getResponse();
        }));
    }

    @Override
    public int getOrder() {
        return 5000;
    }
}
